home *** CD-ROM | disk | FTP | other *** search
- /*
- IC Generic Overide.c
-
- C port of ICGenericOverride.p, file comment follows below.
-
- I ported all of IC to C, so I figured I might as well do the same
- for all of the other little pieces.
-
- History:
- 11/17/95 dhn - Started port.
- */
-
- /*
- Internet Config Generic Overide Component
-
- Routine names have an ICGO prefix for Internet Config Generic Override.
-
- This component is the framework for an Internet Config override
- component. I've used it to replace the original IC ReadOnly and
- IC RandomSignature components bodies with one common body.
- The different between the two components is now contained isolated
- in a separate file, ICSpecificOverride.
-
- The component overrides the Internet Config Extension and
- passes all calls through to the specific override to determine
- whether it should be overridden.
-
- This code has followed a fairly long path--Jager was the one who
- originally started the work on the Random Signature component.
- I based my code on his code and tried to get it work, in the
- process finding and using some sample code from a develop article.
- Eric translated the generic parts of Random Signature to C to
- implement a component of his own (fixing bugs and rewriting along
- the way), and then modified to duplicate the behavior of
- IC ReadOnly. Since then I have ported the changes back to Pascal
- to form the basis of this generic override component, which I've
- used for the IC 1.1 override components.
-
- Consider it a collaborative work, as Eric
- says "a bit of a Frankenstein's monster".
-
- This release fixes a nasty bug in the Pascal example components, one which
- prevents them from loading if their manufacturer code comes after
- that of a previously registered component. If you use any component
- based on this code, the old versions of IC ReadOnly and Random
- Signature will probably stop working.
-
- If you're implementing a component of your own, I strongly suggest
- you contact either Eric or myself first. In any event, read
- the section on the component manager in Inside Macintosh: More
- Macintosh Toolbox very closely and test your component thoroughly.
- You'll definitely want some tools off of develop 15, including
- Komponent Killer, Reinstaller II and the "thing" dcmd.
-
- This code is probably of adequate quality for most uses, but if
- you are using it to implement a commercial-quality system, you
- may want to rewrite it from the ground up.
-
- Quinn "The Eskimo!"
-
- with vast plagarism from...
-
- Eric Kidd
- eric.kidd@dartmouth.edu
-
- Thanks for all the work Eric!
-
- */
-
- #include <Components.h>
- #include <Folders.h>
-
- #if USESROUTINEDESCRIPTORS
- #include <stdlib.h>
- #endif
-
- #include "IC Keys.h"
- #include "IC Component Selectors.h"
- #include "IC Component API.h"
-
- #include "IC Generic Override.h"
- #include "IC Specific Override.h"
-
- // #include "IC Component Utils.h"
-
- /*
- ICGOFixCloneRefCon
-
- See Inside Macintosh: More Macintosh Toolbox p. 6-35 for
- an overview of this silliness. It seems that when your globally-
- registered component is opened by an application, the system
- pulls a fast one under "certain circumstances" (not enough memory
- in the system heap) and "clones" a locally-registered version
- of your component, frying your RefCon in process.
-
- What we need to do is determine if this is the case, and if so,
- recover the RefCon by locating the original copy of the component.
-
- The Officially Sactioned Way to do this is a bit of a hack. Global
- components have an A5 world of zero when they are opened, but local
- ones have it pre-set to the parent application's value. If your
- supposedly global component detects that it has a pre-set A5 world,
- then it's been cloned.
-
- To find the original copy of the component (which has the RefCon we
- need), we need to find another component that looks exactly like us,
- with the exception of a different component identifier. Unless we've
- been registered globally multiple times under the same name, this
- should work. FindNextComponent will do the job here.
-
- The "practical upshot" of this:
- 1) Only call this routine when handling open messages
- 2) Call it before setting your instance's A5 world
- 3) Only call it if you should have been global
- 4) It won't work if you've been registered multiple times
- under the same name.
- 5) Don't use the same manufacturer code for different
- components with the same type/subtype
- 6) It may not work at all. I'm a college student, dammit, not a
- programming guru.
-
- Eric Kidd
- eric.kidd@dartmouth.edu
- 16 Dec 94
- */
- pascal ComponentResult ICGOFixCloneRefCon(ComponentInstance self){
- OSErr err=noErr;
- ComponentDescription cd;
- Component current;
-
- if ((GetComponentRefcon((Component)self)==0)&&(GetComponentInstanceA5(self)!=0)){
- // if this component has not been opened & setup and we've been cloned
-
- // get enough info about ourself to recognize the original
- GetComponentInfo((Component)self,&cd,0,0,0);
- cd.componentFlagsMask=0L; // these shouldn't be relevant
-
- current=(Component)0;
-
- do {
- // loop until we find someone other than ourself
- current=FindNextComponent(current,&cd);
-
- if (current==(Component)0){
- // We didn't find any original--this happens often.
- // If we've been captured, we can't find the original copy.
- // Best thing to do is return an error.
- return paramErr;
- }
- } while (current!=(Component)self);
-
- if (current!=(Component)0)
- SetComponentRefcon((Component)self,GetComponentRefcon(current));
-
- err=noErr;
- }
-
- return err;
- }
-
- /*
- If the shared globals have not yet been allocated, we'll try to set them up and return them.
- */
- pascal ComponentResult ICGOGetSharedGlobals(GlobalsHandle globals){
- ComponentResult err;
- SharedGlobalsPtr shared;
-
- shared=(SharedGlobalsPtr)GetComponentRefcon((Component)(*globals)->self);
- (*globals)->shared=shared;
-
- if (shared==(SharedGlobalsPtr)0){
- shared=(SharedGlobalsPtr)NewPtrSysClear(sizeof(SharedGlobals));
- err=MemError();
- (*globals)->shared=(SharedGlobalsPtr)0;
-
- if (err!=noErr)
- return err;
-
- (*globals)->shared=shared;
-
- // init our part of the shared globals
- shared->delegate=0;
-
- // and remember the shared globals in our refcon
-
- SetComponentRefcon((Component)(*globals)->self,(long)shared);
-
- // Since our shared globals get set up only once at registration time,
- // here's the perfect place to move ourselves to the default position in the component list
-
- err=SetDefaultComponent((Component)(*globals)->self,defaultComponentIdentical+defaultComponentAnyFlagsAnyManufacturer);
-
- if (err==noErr)
- ICSOInitShared(globals);
- }
-
- return err;
- }
-
- // Component Manager Routines
-
- /*
- I'd love to allocate shared globals here, but certain versions of the Component Manager
- don't call ICGORegister. Additionally, calls to ICGOOpen and ICGOClose bracket the call if it
- does get made. Go Figure.
-
- We actually return a boolean value, false if we should be registered and true if we shouldn't.
- */
- pascal ComponentResult ICGORegister(GlobalsHandle globals){
-
- return (ComponentResult)false;
- }
-
- /*
- Eric's comment:
- Does this break if we've been cloned? Does the clone get unregistered seperately and double dispose? Hmm.
- FIIK )-:
- */
- pascal ComponentResult ICGOUnregister(GlobalsHandle globals){
- ComponentResult result=-1,result2;
-
- if ((*globals)->shared!=(SharedGlobalsPtr)0){
- // give the specifics opportunity to clean up its shared globals
-
- result=ICSOCleanShared(globals);
-
- // clean up our part of the shared globals
- result2=UncaptureComponent((*globals)->shared->delegate);
-
- if (result==noErr)
- result=result2;
-
- // dispose of the shared globals and set our refcon back to zero
-
- DisposePtr((Ptr)(*globals)->shared);
- SetComponentRefcon((Component)(*globals)->self,0L);
- }
-
- return result;
- }
-
- /*
- Handle the Component Manager CanDo request.
- */
- pascal ComponentResult ICGOCanDo(GlobalsHandle globals,short selector){
- ComponentResult result;
-
- switch (selector){
- case kComponentUnregisterSelect:
- case kComponentOpenSelect:
- result=(ComponentResult)1;
- break;
- default:
- result=ICSOCanDo(globals,selector);
-
- if (result==delegateThisCallErr)
- result=ComponentFunctionImplemented((*globals)->delegate,selector);
- else
- result++;
- break;
- }
-
- return result;
- }
-
- pascal Component ICGOFindDelegate(Component after){
- ComponentDescription cd;
- ComponentDescription found_cd;
- Component current;
- Boolean found=false;
-
- cd.componentType=internetConfigurationComponentType;
- cd.componentSubType=internetConfigurationComponentSubType;
- cd.componentManufacturer=(OSType)0;
- cd.componentFlags=0L;
- cd.componentFlagsMask=0L;
-
- current=after;
-
- do {
- current=FindNextComponent(current,&cd);
-
- if (current!=(Component)0){
- if (GetComponentInfo(current,&found_cd,0,0,0)==noErr){
- found=(found_cd.componentManufacturer!=kOurComponentManufacturer);
- }
- }
- } while ((!found)&&(current!=(Component)0));
-
- if (current==(Component)0){
- // DebugStr("\pICGOFindDelegate failed to find one.");
- }
-
- return current;
- }
-
- /*
- ICGOOpen
-
- This function has been substantially recrafted from the original. Cloning
- is now handled correctly (see the description of ICGOFixCloneRefCon and error
- handling has been made more graceful by the addition of a dedicated control
- structure. A memory leak has been closed and OpenComponent can no longer
- be called on a NULL component instance.
-
- If you're using the pascal version, you'll want to carefully examine the differences.
- */
- pascal ComponentResult ICGOOpen(GlobalsHandle globals,ComponentInstance self){
- ComponentResult err;
- Component cap,toCapture;
-
- globals=(GlobalsHandle)0;
- err=ICGOFixCloneRefCon(self);
-
- if (err==noErr){
- globals=(GlobalsHandle)NewHandleClear(sizeof(GlobalsRecord));
- err=MemError();
- }
-
- if (err==noErr){
- HLock((Handle)globals);
- (*globals)->self=self;
- SetComponentInstanceStorage(self,(Handle)globals);
- err=ICGOGetSharedGlobals(globals);
- }
-
- if (err==noErr){
- // if we haven't yet done so, find and capture the topmost IC component. We'll
- // save the special component identifier which will permit us to open it.
-
- if ((*globals)->shared->delegate==0){
- toCapture=ICGOFindDelegate((Component)self);
-
- if (toCapture==(Component)0)
- err=icNothingToOverrideErr;
- else
- (*globals)->shared->delegate=CaptureComponent(toCapture,(Component)self);
- }
-
- if (err==noErr){
- (*globals)->delegate=OpenComponent((*globals)->shared->delegate);
- err=ComponentSetTarget(self,self);
- }
- if (err==noErr)
- err=ICSOInitGlobals(globals);
- }
-
- if (globals!=(GlobalsHandle)0)
- HUnlock((Handle)globals);
-
- if (err!=noErr){
- if (globals!=(GlobalsHandle)0){
- DisposeHandle((Handle)globals);
- SetComponentInstanceStorage(self,(Handle)0);
- }
- }
-
- return err;
- }
-
- // handle the close request
- pascal ComponentResult ICGOClose(GlobalsHandle globals,ComponentInstance self){
- if (globals!=(GlobalsHandle)0){
- ICSOCleanGlobals(globals);
-
- if ((*globals)->delegate!=0)
- CloseComponent((*globals)->delegate);
-
- DisposeHandle((Handle)globals);
- }
-
- return noErr;
- }
-
- // handle the target request
- pascal ComponentResult ICGOTarget(GlobalsHandle globals,ComponentInstance new_target){
- ComponentResult err=noErr;
-
- (*globals)->target=new_target;
-
- if ((*globals)->delegate!=0)
- err=ComponentSetTarget((*globals)->delegate,new_target);
-
- return err;
- }
-
- // Internet Configuration specific routines
-
- pascal ComponentResult main(ComponentParameters* params,Handle storage){
- SignedByte s;
- ComponentFunctionUPP proc;
- ComponentResult res;
-
- #if USESROUTINEDESCRIPTORS
- __rsrcinit();
- #endif
-
- proc=(ComponentFunctionUPP)0;
-
- // DebugStr(SelectorToStr(params->what));
-
- switch (params->what){
- // Component Manager Stuff
-
- case kComponentVersionSelect:
- res=internetConfigurationComponentInterfaceVersion;
- break;
- case kComponentCanDoSelect:
- proc=BuildNewProc(ICGOCanDo,uppICGOShortProcInfo);
- break;
- case kComponentOpenSelect:
- proc=BuildNewProc(ICGOOpen,uppICGOInstanceProcInfo);
- break;
- case kComponentCloseSelect:
- proc=BuildNewProc(ICGOClose,uppICGOInstanceProcInfo);
- break;
- case kComponentTargetSelect:
- proc=BuildNewProc(ICGOTarget,uppICGOInstanceProcInfo);
- break;
- case kComponentRegisterSelect:
- proc=BuildNewProc(ICGORegister,uppICGOGlobalsProcInfo);
- break;
- case kComponentUnregisterSelect:
- proc=BuildNewProc(ICGOUnregister,uppICGOGlobalsProcInfo);
- break;
-
- // this component type stuff
- default:
- proc=ICSOWhatToOverride((GlobalsHandle)storage,params->what);
- break;
- }
-
- if (storage!=(Handle)0){
- s=HGetState(storage);
- HLock(storage);
- }
-
- res=delegateThisCallErr;
-
- if (proc!=(ComponentFunctionUPP)0){
- res=CallComponentFunctionWithStorage(storage,params,proc);
- DisposeRoutineDescriptor((UniversalProcPtr)proc);
- }
-
- if ((storage!=(Handle)0)&&(params->what!=kComponentCloseSelect)){
- HSetState(storage,s);
- }
-
- #if USESROUTINEDESCRIPTORS
- __rsrcterm();
- #endif
-
- return res;
- }
-